﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Utils
{
    /// <summary>
    /// 模型验证
    /// </summary>
    public static class VerifyUtil
    {
        /// <summary>
        /// 创建一个验证模型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static Verify<T> Verify<T>(T dto) where T : class, new()
        {
            return new Verify<T>(dto);
        }
    }

    public class Verify<T>
    {
        private T self;

        private readonly Dictionary<string, string> matchs = new Dictionary<string, string>();

        public Verify(T dto)
        {
            if (dto == null)
            {
                throw Error.DefaultError("缺少验证对象");
            }
            self = dto;
        }

        private string GetDisplayName(MemberInfo info)
        {
            var displayName = info.GetCustomAttribute<System.ComponentModel.DisplayNameAttribute>();
            return displayName == null ? info.Name : displayName.DisplayName;
        }

        /// <summary>
        /// 非空验证
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="selector"></param>
        /// <param name="message"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public Verify<T> Required<TKey>(Expression<Func<T, TKey>> selector, string message = null, bool condition = true)
        {
            if (!condition)
            {
                return this;
            }
            MemberInfo info = (selector.Body as MemberExpression).Member;
            if (matchs.ContainsKey(info.Name)) return this;
            var value = selector.Compile().Invoke(self);
            if (value == null)
            {
                matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}不能为空");
            }
            else if (value is string)
            {
                if (string.IsNullOrWhiteSpace(value as string))
                {
                    matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}不能为空");
                }
            }
            else if (value.Equals(default(TKey)))
            {
                matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}不能为空");
            }
            else if (value is IEnumerable ie && !ie.GetEnumerator().MoveNext())
            {
                matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}不能为空");
            }
            return this;
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        /// <param name="selector"></param>
        /// <param name="check"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public Verify<T> IsMatch<KEY>(Expression<Func<T, KEY>> selector, Func<bool> check, string message = null, bool condition = true)
        {
            if (!condition)
            {
                return this;
            }
            MemberInfo info = (selector.Body as MemberExpression).Member;
            if (matchs.ContainsKey(info.Name)) return this;
            if (check())
            {
                matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}有误");
            }
            return this;
        }


        /// <summary>
        /// 正则判断
        /// </summary>
        /// <param name="selector"></param>
        /// <param name="pattern"></param>
        /// <param name="message"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public Verify<T> IsMatch(Expression<Func<T, string>> selector, Regex regex, string message = null, bool condition = true)
        {
            if (!condition)
            {
                return this;
            }
            MemberInfo info = (selector.Body as MemberExpression).Member;
            if (matchs.ContainsKey(info.Name)) return this;
            var value = selector.Compile().Invoke(self);
            if (!regex.IsMatch(value.ToString()))
            {
                matchs.Add(info.Name, message ?? $"{GetDisplayName(info)}有误");
            }
            return this;
        }

        public void ThrowInputError()
        {
            if (matchs.Count > 0)
            {
                throw Error.ArgumentsError(matchs);
            }
        }

    }
}
